package com.yingxue.demo.shiro;

import com.yingxue.demo.constant.Constant;
import com.yingxue.demo.exception.BizException;
import com.yingxue.demo.exception.enums.UnauthorizedExceptionEnum;
import com.yingxue.demo.util.JWTUtil;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;

/**
 * @Package: com.company.demo.shiro
 * @Author: Mr.Waves
 * @Date: 2020-03-13 10:04
 * @Description:
 **/
public class CustomHashedCredentialsMatcher extends HashedCredentialsMatcher {
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        CustomUsernamePasswordToken customUsernamePasswordToken = (CustomUsernamePasswordToken) token;
        String accessToken = (String) customUsernamePasswordToken.getPrincipal();
        String userId = JWTUtil.getUserId(accessToken);
        // 判断账号是否被锁定
        if (redisTemplate.hasKey(Constant.ACCOUNT_LOCKED_KEY + userId)) {
            throw new BizException(UnauthorizedExceptionEnum.ACCOUNT_LOCKED);
        }
        // 判断账号是否被删除
        if (redisTemplate.hasKey(Constant.ACCOUNT_DELETED_KEY + userId)) {
            throw new BizException(UnauthorizedExceptionEnum.ACCOUNT_DELETED);
        }
        // 判断账号是否已主动登出
        if (redisTemplate.hasKey(Constant.JWT_ACCESS_TOKEN_BLACKLIST + accessToken)) {
            throw new BizException(UnauthorizedExceptionEnum.TOKEN_INVALID);
        }
        // 判断访问凭证(accessToken)是否有效
        if (!JWTUtil.validateToken(accessToken)) {
            throw new BizException(UnauthorizedExceptionEnum.TOKEN_INVALID);
        }
        // 判断账号是否需要主动刷新访问凭证
        if (redisTemplate.hasKey(Constant.JWT_REFRESH_KEY + userId) && redisTemplate.getExpire(Constant.JWT_REFRESH_KEY + userId, TimeUnit.MILLISECONDS) > JWTUtil.getRemainingTime(accessToken)) {
            // 账号的访问凭证是否已经刷新过
            if (!redisTemplate.hasKey(Constant.JWT_REFRESH_IDENTIFICATION + accessToken)) {
                throw new BizException(UnauthorizedExceptionEnum.TOKEN_INVALID);
            }
        }
        return true;
    }
}
